What is C++?

Andersama Saturday, May 9, 2026

C++ is a programming language. That’s the extremely short answer. The longer answer is that it’s a successor to C. It started out as a project to expand on C’s versatility by introducing “classes”, the original name of C++ was “C with Classes”. This was an expansion on C’s “structs”. Due to the mostly backwards compatible nature of C++ “classes” and “structs” are the same thing to a C++ compiler.

So what did “classes” introduce? In many programming languages including C, structs are simply a way of describing to the compiler program the software developer’s intended memory layout for variables. Structs neatly group several variables by name, and for the most part, programs execute code and accomplish their tasks by modifying memory. So how a program is laid out in memory can become incredibly important for how a program performs. This is true of any programming or scripting language, although some don’t necessarily give the developer complete control.

C++ expanded on structs, where “structs” may be thought of as strictly data. “Classes” are a combination of structs and the functions which would otherwise be paired along with them. This idea isn’t unique to C++, however in C, the executable code that resides in functions is just that. The software developer writes code incorporating the structs they’ve defined for ease of use and the two concepts of data and code are in essence separate.

Here’s a quick side by side example of C and C++ (bare in mind C++ is fully capable of running the C code).

struct time {
    int year;
    int month;
    int day;
};

void set_time(time* t, int year, int month, int day) {
    t->year = year;
    t->month = month;
    t->day = day;
};

int main(void) {
    time sometime;
    set_time(&sometime, 2026, 5, 10);
    return 0;
}
struct time {
    int year;
    int month;
    int day;

    void set_time(int year, int month, int day) {
        this->year = year;
        this->month = month;
        this->day = day;
    }
};

int main(void) {
    time sometime;
    sometime.set_time(2026, 5, 10);
    return 0;
}

The functions C++ defines related to its “structs” are simply a shorthand for what many C developers would otherwise do. Typically C developers would have included a pointer to the struct (this is the time* t parameter) they’d like to modify (probably the first one). So C++‘s approach to creating these functions bound to particular structs is exactly that. Secretly behind the scenes C++ creates a function with an additional leading parameter being a pointer to the struct, and reserves the word “this” so programmers can refer to it. This can help disambiguate what the developer intended to do.

/* Here, had we not used this-> the compiler might not have been sure that which variables were intended, the struct's or the function parameters */
this->year = year;
this->month = month;
this->day = day;

But that’s a niche thing, the key point is this, the compiler now has a (probably short) list of functions that the software developer can call upon. Which the compiler may give feedback about! This can be helpful in an integrated development environment where hovering a mouse over a section of code might give tooltips!

sometime.set_time(2026, 5, 10);

Aside from the niceties in an IDE, software developers can do something in C++ that they couldn’t in C, now they can reuse function names in their code! In order to keep the backwards compatibility with C, and to allow different structs to share the same function names, C++ creates a naming scheme for its functions. If the function is not related to a struct, it takes the name verbatim as C would do, no change here, no problem. Otherwise C++ performs a task of “name-mangling”, using the whole of the function’s signature, including the names of the types of the parameters! (Types are another name for structs!) It’s called name-mangling because the end result would look nothing like the easy to read set_time. C++ can then determine which function to execute by determining the type of the struct and the parameters, at least those which are logically deducible. Over the years improvements to C++‘s compilers have improved on the compiler’s deductive capabilities, allowing for even more interesting flexibility in accomplishing tasks in a well defined manner that in C would require the software developer careful consideration.

These include things like virtual functions, the idea of a function which can change at runtime. C Software developers can do this, but they would need to define their own approach and be very careful about misuse at runtime. In C++ the concept is well understood, so the compiler can do the heavy lifting, this includes incorporating a virtual function table into the struct. Much like how C++ secretly incorporates a pointer into method functions, it can do the same for a struct, adding additional data members for each virtual function.

But reusing function names isn’t just handy between structs. It also helps when software developers want to generalize. For example, serializing data to text would becomes frustrating if each function needed to be remembered by name, but also it may be trivial to work out a repeatable pattern.

Take C’s standard library of functions for example, there’s a short list of them, but they’re often turned almost into mnemonics because of how many types the compiler already has to work with! strtod strtof strtoi are all functions to convert strings to numerical values! In a way, a lot of C api’s might look like name-mangled code! But the core of the code could just as easily be shared, and or common parts repeated. In C++ a developer might create an api of functions with the same output goal, but with varying inputs via a template, and allow the compiler to do the work of dealing with the different types!

template<typename T>
void print(T& value) {
    std::cout << value;
}

Here for example this template assumes that for any given type there’s an operator << function which can handle outputting value to std::cout. A developer might expand on this and specialize the template for a specific type. Then if needed and have a template as a fallback for any type.

There is however a downside to this approach, as C++‘s feature set expands and becomes more and more difficult to parse, it becomes more and more difficult to integrate C++ functions into other languages. This is because name-mangling requires determining the names of types, ultimately a program which is capable of parsing C++ correctly to determine the correct name for a name-mangled function is nearly identical to a fully fledged C++ compiler! This is why although C is very old, it is still incredibly integral to software development today. While C++ may be ease to use, C without having any name-mangling to speak of, is incredibly simple to incorporate into other programs.